//
// Created by mayunxi on 2020/6/8.
//
#include <sys/stat.h>
#include <iostream>
#include "Decoder.h"

char g_ffmpeg_err[PRINTF_BUFFER_SIZE];
int m_thread_exit = 0;
int m_thread_pause = 0;


#if USE_LOG4PLUS

#else
int g_logger;
void LOG4CPLUS_ERROR(int log, string msg)
{
    cout << msg << endl;
}
void LOG4CPLUS_WARN(int log, string msg)
{
    cout << msg << endl;
}
#endif // 
/************************************************************************
**函数：interrupt_callback
**功能：avformat_open_input连接超时回调函数
**参数：
       [in] void *p - interrupt_callback.opaque传递的参数
**返回：
       1表示中断，0表示继续执行
**备注：
    1). 回调函数
************************************************************************/
int interrupt_callback(void *p) {
    Runner *r = (Runner *)p;
    if (r->lasttime > 0) {
        if (time(NULL) - r->lasttime > 5) {
            // 等待超过4s则中断
            memcpy(g_ffmpeg_err,"time out,avformat_open_input end block",strlen("time out,avformat_open_input end block"));
            return 1;
        }
    }
    return 0;
}

Decoder::Decoder(CHANNEL_INFO_SET channel_info):m_channel_set(channel_info)
{
    
    //ParseRtsp();
}
/************************************************************************
**函数：FreeResource
**功能：释放资源
**参数：
       void
**返回：
       void
**备注：
    1). CPU/GPU版本的公共资源
************************************************************************/
void Decoder::FreeResource() {
    //等待线程结束，释放自己的资源后，再手动释放ffmpeg相关资源
    if (m_avframe != NULL) {
        //LOG4CPLUS_INFO(g_logger,"channel_" << m_channel_num << " free AVFrame");
        av_frame_free(&m_avframe);
        m_avframe = NULL;
    }

    //同时释放了由AVFormatContext得到的内存，如pAVCodecContext
    if (m_input_avfmt_ctx!=NULL) {
       // LOG4CPLUS_INFO(g_logger,"channel_" << m_channel_num << " free AVFormatContext");
        avformat_close_input(&m_input_avfmt_ctx);
        m_input_avfmt_ctx = NULL;
    }
    if (m_opts != NULL)
    {
       // LOG4CPLUS_INFO(g_logger,"channel_" << m_channel_num << " free AVDictionary");
        av_dict_free(&m_opts);
        m_opts = NULL;
    }

    if (m_out_fmt_ctx) {
        //LOG4CPLUS_INFO(g_logger,"channel_" << m_channel_num << " free m_out_fmt_ctx");
        avformat_close_input(&m_out_fmt_ctx);
        m_out_fmt_ctx = NULL;
    }

    //编码
    if (m_enc_ctx)
    {
       // LOG4CPLUS_INFO(g_logger,"channel_" << m_channel_num << " free m_enc_ctx");
        avcodec_free_context(&m_enc_ctx);
        m_enc_ctx = NULL;
    }

    //转换
    if (m_img_convert_ctx)
    {
        sws_freeContext(m_img_convert_ctx);
        m_img_convert_ctx = NULL;
    }
    if (m_out_buffer)
    {
        av_free(m_out_buffer);
    }
    if (m_pFrameYUV)
    {
        av_frame_free(&m_pFrameYUV);
    }

}

Decoder::~Decoder() {
    FreeResource();
}
/************************************************************************
**函数：ParseRtsp
**功能：分解rtsp地址，提取ip等信息
**参数：
       void
**返回：
       true成功，false失败
**备注：
************************************************************************/
bool Decoder::ParseRtsp() {
    // get host
    if (m_channel_set.rtsp_url.compare(0,strlen("rtsp://"),"rtsp://") != 0)
    {
        m_channel_set.rtsp_url_ok = false;
        return false;
    }
    string tmp_url;
    size_t pos = 0;
    size_t a = m_channel_set.rtsp_url.find_last_of('@');
    if (a != -1)
    {
        tmp_url = m_channel_set.rtsp_url.substr(a+1);
        string tmp = "rtsp://"  + tmp_url;
        //memcpy(rtspInfo._url,tmp.c_str(),tmp.length());

        //user passwd
        string usr_info = m_channel_set.rtsp_url.substr(7,a-7);
        pos = usr_info.find(":");
        string tmp_usr = usr_info.substr(0,pos);
        string tmp_passwd = usr_info.substr(pos+1);
        memcpy(m_rtsp_info.usr,tmp_usr.c_str(),tmp_usr.length());
        memcpy(m_rtsp_info.passwd,tmp_passwd.c_str(),tmp_passwd.length());
        //printf("usr:%s,passwd:%s\n",m_rtsp_info.usr,m_rtsp_info.passwd);
        //ip
        pos = m_channel_set.rtsp_url.find_first_of("/",a);
        m_rtsp_info.ip = m_channel_set.rtsp_url.substr(a+1,pos-a-1);

    }
    else
    {
        memcpy(m_rtsp_info._url,m_channel_set.rtsp_url.c_str(),m_channel_set.rtsp_url.length());

        //ip
        size_t b = m_channel_set.rtsp_url.find_first_of('/',7);
        m_rtsp_info.ip = m_channel_set.rtsp_url.substr(7,b-7);
    }
    m_channel_set.rtsp_url_ok = true;
    return true;
}
/************************************************************************
**函数：FFMPEG_Callback
**功能：FFMPEG日志回调函数
**参数：
**返回：
**备注：
************************************************************************/
void FFMPEG_Callback(void* ptr, int level, const char* fmt, va_list vl)
{
    // 可以根据level的级别选择要打印显示的内容
    if (level <= 16)
    {
        char buffer[1024];
        vsprintf(buffer, fmt, vl);
        int len = strlen(buffer);
        buffer[len-1] = 0;
        memset(g_ffmpeg_err,0,PRINTF_BUFFER_SIZE);
        sprintf(g_ffmpeg_err,"ffmpeg level %d,%s",level,buffer);
        LOG4CPLUS_ERROR(g_logger,g_ffmpeg_err );
    }
}
/************************************************************************
**函数：GlobalInit
**功能：编解码器全局初始化
**参数：
       void
**返回：
       void
**备注：
    1). 程序启动时，只需调用一次
************************************************************************/
void Decoder::GlobalInit(void)
{
    //av_log_set_callback(FFMPEG_Callback);  // 设置自定义的日志输出方法
    //av_log_set_level(g_sys_config.m_ffm_log_level); //打印级别
    //LOG4CPLUS_INFO(g_logger,"ffmepg loglevel "<< av_log_get_level());
    //以前ffmpeg初始化相关av_regigser_all,av_register_xxx都废弃了，新的ffmpeg版本不需要av_regigser这个方式注册这个流程了。
    av_register_all();         //初始化FFMPEG  调用了这个才能正常适用编码器和解码器
    avformat_network_init();   //初始化网络流格式,使用RTSP网络流时必须先执行
}



//显示相关

SDL_Renderer* m_sdlRenderer;
SDL_Texture* m_sdlTexture;
SDL_Event m_event;

static int sfp_refresh_thread(void* opaque) {
    m_thread_exit = 0;
    m_thread_pause = 0;

    while (!m_thread_exit) {
        if (!m_thread_pause) {
            SDL_Event event;
            event.type = SFM_REFRESH_EVENT;
            SDL_PushEvent(&event);
        }
        //std::cout << "delay" << endl;
        SDL_Delay(40);
    }
    m_thread_exit = 0;
    m_thread_pause = 0;
    //Break
    SDL_Event event;
    event.type = SFM_BREAK_EVENT;
    SDL_PushEvent(&event);

    return 0;
}
bool DisplayInit(int width,int height)
{
    //------------SDL----------------
    int screen_w, screen_h;
    SDL_Window* screen;

    SDL_Rect sdlRect;
    SDL_Thread* video_tid;

    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
        printf("Could not initialize SDL - %s\n", SDL_GetError());
        return -1;
    }
    //SDL 2.0 Support for multiple windows
    screen_w = width;
    screen_h = height;
    screen = SDL_CreateWindow("Simplest ffmpeg player's Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
        screen_w, screen_h, SDL_WINDOW_OPENGL);

    if (!screen) {
        printf("SDL: could not create window - exiting:%s\n", SDL_GetError());
        return -1;
    }
    m_sdlRenderer = SDL_CreateRenderer(screen, -1, 0);
    //IYUV: Y + U + V  (3 planes)
    //YV12: Y + V + U  (3 planes)
    m_sdlTexture = SDL_CreateTexture(m_sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, width, height);

    sdlRect.x = 0;
    sdlRect.y = 0;
    sdlRect.w = screen_w;
    sdlRect.h = screen_h;
    video_tid = SDL_CreateThread(sfp_refresh_thread, NULL, NULL);

    //------------SDL End------------
 

    return true;
}

void Display(AVFrame* frame)
{
   
    //SDL---------------------------
    SDL_UpdateTexture(m_sdlTexture, NULL, frame->data[0], frame->linesize[0]);
    SDL_RenderClear(m_sdlRenderer);
    //SDL_RenderCopy( sdlRenderer, sdlTexture, &sdlRect, &sdlRect );  
    SDL_RenderCopy(m_sdlRenderer, m_sdlTexture, NULL, NULL);
    SDL_RenderPresent(m_sdlRenderer);
    //SDL End-----------------------
}